#!/bin/bash
set -o errexit

# 用法说明
function usage(){
    echo "usage:"
    echo "  $0 <options> <vm-uuid>"
    echo "      options:"
    echo "          -t|--target-host <TARGETHOST> 目录主机"
    echo "      vm-uuid 要迁移的虚拟机 uuid"    
    echo "     --help|-h 显示使用帮助，可选"
    echo ""
    echo "     本脚本在SmartOS(非Triton)下运行"    
    echo "     源主机和目标主机之间必须已配置好免密登录"    
    echo ""
    echo "     使用示例："
    echo "          $0 -t 192.168.18.18 1e65c912-3123-11eb-a066-4338f21c17e7"
    echo "              迁移虚拟机 1e65c912-3123-11eb-a066-4338f21c17e7 到目标SmartOS主机 192.168.18.18"    
    echo "          $0 -h"
    echo "              显示命令使用帮助"
    exit
}

# 出错提示
function fatal(){
    echo ""
    echo "$1"
    exit 1
}


function count_speed(){
    local started_at=$1
    
    local elapsed=$(($(date +%s) - ${started_at}))
    
    local msg="cost: ${elapsed}s"        
    
    local p_size=$2
    if [ "${p_size}" != "" ]; then
        local p_speed=5
        local p_unit='MB/s'
        if [ "${elapsed}" != "0" ];then
            p_speed=$((p_size / elapsed))
            if [[ $p_speed -gt 1024*1024 ]];then
                p_speed=$(awk 'BEGIN{printf("%.2f",'$p_size' / '$elapsed' / 1024 / 1024)}')
                p_unit='MB/s'
            elif [ $p_speed -gt 1024 ];then
                p_speed=$(awk 'BEGIN{printf("%.2f",'$p_size' / '$elapsed' / 1024)}')
                p_unit='KB/s'
            else
                p_speed=$(awk 'BEGIN{printf("%.2f",'$p_size' / '$elapsed')}')
                p_unit='B/s'
            fi
        fi
        msg="${p_speed}${p_unit} cost: ${elapsed}s"
    fi
    echo "${msg}"
}

function auto_migration(){
    vmadm send ${vm_uuid} |ssh -c aes128-gcm@openssh.com ${target_host} 'vmadm receive'
    ssh ${target_host} 'vmadm stop ${vm_uuid}'
    ssh ${target_host} "zfs create -o quota=1000m -o compression=gzip -o mountpoint=/zones/${vm_uuid}/cores zones/cores/${vm_uuid}"
    ssh ${target_host} 'vmadm start ${vm_uuid}'
}

function manual_migration(){
    zonecfg -z ${vm_uuid} export > ${vm_uuid}.zcfg

    zfs destroy -r zones/${vm_uuid}@migration || true
    zfs snapshot -r zones/${vm_uuid}@migration

    echo "发送数据集 ..."
    zfs send -R -I zones/${image_uuid}@final zones/${vm_uuid}@migration | ssh -c aes128-gcm@openssh.com ${target_host} 'zfs recv -d zones'
    # 如果由于某种原因无法在目标主机上导入image，则可以进行完整发送：
    # zfs send -R zones/${vm_uuid}@migration | ssh -c aes128-gcm@openssh.com ${target_host} 'zfs recv -d zones'

    vm_state=$(vmadm get ${vm_uuid} | json state)
    if [ "${vm_state}" == "running" ]; then
        vmadm stop ${vm_uuid}
        zfs snapshot -r zones/${vm_uuid}@delta
        zfs send -R -I zones/${vm_uuid}@migration zones/${vm_uuid}@delta | ssh -c aes128-gcm@openssh.com ${target_host} 'zfs recv -d zones'
    fi

    scp ${vm_uuid}.zcfg ${target_host}:~/

    echo "在目标主机导入虚拟机 ..."
    ssh ${target_host} "zonecfg -z ${vm_uuid} -f ~/${vm_uuid}.zcfg"

    # ssh ${target_host} vi /etc/zones/index
    # ssh ${target_host} svcadm restart vminfod
    # 
    ssh ${target_host} zoneadm -z ${vm_uuid} attach

    ssh ${target_host} "vmadm start ${vm_uuid}"

    ssh ${target_host} "zfs destroy -r zones/${vm_uuid}@migration"
    zfs destroy -r zones/${vm_uuid}@migration
}

# 程序执行开始时间
BEGIN_AT=$(date +%s)
# 如果快照存在，是否用现有快照克隆
target_host=
vm_uuid=
# 选项处理
while [[ $# -ge 1 ]]; do
    case $1 in
        -t|--target-host )
                target_host=$2
                shift 2
                ;;        
        -h|--help )
                usage
                ;;
        * )
            if [ $# -eq 1 ]; then
                vm_uuid=$1
                shift
            else
                echo "不支持的参数 $1"
                usage                
            fi
            ;;
    esac
done

# 预处理源虚拟机
if [ "${vm_uuid}" == "" ]; then    
    echo "没有提供vm uuid "
    usage    
fi

if [ "${target_host}" == "" ]; then    
    echo "没有提供目标主机 "
    usage    
fi


[[ "$(ssh ${target_host} vmadm list -Ho alias uuid=${vm_uuid})" == "" ]] || fatal "目标主机 {target_host} 已存在uuid为${target_uuid}的虚拟机"


image_uuid=$(vmadm get ${vm_uuid} | json image_uuid)
 
echo "import image ${image_uuid} on ${image_uuid} ..."
ssh ${target_host} imgadm import ${image_uuid}

manual_migration
echo "迁移完成, 请检查目标虚拟机是否正常, 并删除源虚拟机 或 清除目标虚拟机"